import requests
import logging
import traceback
from typing import Dict, List, Optional, Any
from django.conf import settings

logger = logging.getLogger(__name__)


class GitLabAPIClient:
    """GitLab API客户端"""

    def __init__(self, url: str, token: str):
        self.url = url.rstrip('/')
        self.token = token
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        })

    def _make_request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
        """发送API请求"""
        url = f"{self.url}/api/v4/{endpoint.lstrip('/')}"

        try:
            response = self.session.request(method, url, timeout=30, **kwargs)
            response.raise_for_status()

            if response.content:
                return response.json()
            return {}

        except requests.exceptions.RequestException as e:
            logger.error(f"GitLab API请求失败: {url} - {e}")
            raise Exception(f"GitLab API请求失败: {str(e)}")

    def test_connection(self) -> Dict[str, Any]:
        """测试连接"""
        try:
            user_info = self._make_request('GET', '/user')
            return {
                'success': True,
                'message': '连接成功',
                'user_info': user_info
            }
        except Exception as e:
            return {
                'success': False,
                'message': f'连接失败: {str(e)}'
            }

    def get_projects(self, page: int = 1, per_page: int = 100) -> List[Dict[str, Any]]:
        """获取项目列表"""
        params = {
            'page': page,
            'per_page': per_page,
            'order_by': 'last_activity_at',
            'sort': 'desc'
        }
        return self._make_request('GET', '/projects', params=params)

    def get_project(self, project_id: int) -> Dict[str, Any]:
        """获取单个项目信息"""
        return self._make_request('GET', f'/projects/{project_id}')

    def create_project(self, project_data: Dict[str, Any]) -> Dict[str, Any]:
        """创建项目"""
        return self._make_request('POST', '/projects', json=project_data)

    def update_project(self, project_id: int, project_data: Dict[str, Any]) -> Dict[str, Any]:
        """更新项目"""
        return self._make_request('PUT', f'/projects/{project_id}', json=project_data)

    def delete_project(self, project_id: int) -> Dict[str, Any]:
        """删除项目"""
        return self._make_request('DELETE', f'/projects/{project_id}')

    def create_simple_project(self, name: str, description: str = '', visibility: str = 'private') -> Dict[str, Any]:
        """创建简单的GitLab项目"""
        project_data = {
            'name': name,
            'path': name.lower().replace(' ', '-').replace('_', '-'),
            'description': description,
            'visibility': visibility,
            'initialize_with_readme': True
        }
        return self._make_request('POST', '/projects', json=project_data)

    def get_users(self, page: int = 1, per_page: int = 100) -> List[Dict[str, Any]]:
        """获取用户列表"""
        params = {
            'page': page,
            'per_page': per_page,
            'order_by': 'name',
            'sort': 'asc'
        }
        return self._make_request('GET', '/users', params=params)

    def get_user(self, user_id: int) -> Dict[str, Any]:
        """获取单个用户信息"""
        return self._make_request('GET', f'/users/{user_id}')

    def create_user(self, user_data: Dict[str, Any]) -> Dict[str, Any]:
        """创建用户"""
        return self._make_request('POST', '/users', json=user_data)

    def update_user(self, user_id: int, user_data: Dict[str, Any]) -> Dict[str, Any]:
        """更新用户"""
        return self._make_request('PUT', f'/users/{user_id}', json=user_data)

    def delete_user(self, user_id: int) -> Dict[str, Any]:
        """删除用户"""
        return self._make_request('DELETE', f'/users/{user_id}')

    def get_project_members(self, project_id: int) -> List[Dict[str, Any]]:
        """获取项目成员"""
        return self._make_request('GET', f'/projects/{project_id}/members')

    def add_project_member(self, project_id: int, user_id: int, access_level: int) -> Dict[str, Any]:
        """添加项目成员"""
        data = {
            'user_id': user_id,
            'access_level': access_level
        }
        return self._make_request('POST', f'/projects/{project_id}/members', json=data)

    def update_project_member(self, project_id: int, user_id: int, access_level: int) -> Dict[str, Any]:
        """更新项目成员权限"""
        data = {
            'access_level': access_level
        }
        return self._make_request('PUT', f'/projects/{project_id}/members/{user_id}', json=data)

    def remove_project_member(self, project_id: int, user_id: int) -> Dict[str, Any]:
        """移除项目成员"""
        return self._make_request('DELETE', f'/projects/{project_id}/members/{user_id}')

    def get_branches(self, project_id: int) -> List[Dict[str, Any]]:
        """获取分支列表"""
        return self._make_request('GET', f'/projects/{project_id}/repository/branches')

    def get_tags(self, project_id: int) -> List[Dict[str, Any]]:
        """获取标签列表"""
        return self._make_request('GET', f'/projects/{project_id}/repository/tags')

    def get_commits(self, project_id: int, branch: str = 'main', per_page: int = 100) -> List[Dict[str, Any]]:
        """获取提交记录"""
        params = {
            'ref_name': branch,
            'per_page': per_page,
            'with_stats': True
        }
        return self._make_request('GET', f'/projects/{project_id}/repository/commits', params=params)

    def get_merge_requests(self, project_id: int, state: str = 'all') -> List[Dict[str, Any]]:
        """获取合并请求"""
        params = {
            'state': state,
            'order_by': 'updated_at',
            'sort': 'desc'
        }
        return self._make_request('GET', f'/projects/{project_id}/merge_requests', params=params)

    def create_webhook(self, project_id: int, webhook_url: str) -> Dict[str, Any]:
        """为项目创建Webhook"""
        webhook_data = {
            'url': webhook_url,
            'push_events': True,
            'tag_push_events': True,
            'merge_requests_events': True,
            'pipeline_events': True,
            'wiki_page_events': False,
            'deployment_events': False,
            'job_events': False,
            'releases_events': False,
            'subgroup_events': False,
            'enable_ssl_verification': False,  # 开发环境关闭SSL验证
            'token': '',  # 可以为空
            'push_events_branch_filter': ''  # 不过滤分支
        }
        return self._make_request('POST', f'/projects/{project_id}/hooks', json=webhook_data)

    def get_webhooks(self, project_id: int) -> List[Dict[str, Any]]:
        """获取项目的Webhook列表"""
        return self._make_request('GET', f'/projects/{project_id}/hooks')

    def delete_webhook(self, project_id: int, hook_id: int) -> Dict[str, Any]:
        """删除项目的Webhook"""
        return self._make_request('DELETE', f'/projects/{project_id}/hooks/{hook_id}')


class GitLabAPIManager:
    """GitLab API管理器"""

    def __init__(self, gitlab_server):
        self.gitlab_server = gitlab_server
        self.client = GitLabAPIClient(gitlab_server.url, gitlab_server.token)

    def test_connection(self) -> Dict[str, Any]:
        """测试连接"""
        return self.client.test_connection()

    def create_gitlab_project(self, name: str, description: str = '', visibility: str = 'private') -> Dict[str, Any]:
        """在GitLab上创建新项目"""
        try:
            result = self.client.create_simple_project(name, description, visibility)
            logger.info(f"成功在GitLab上创建项目: {name}")
            return {
                'success': True,
                'message': f'成功创建项目: {name}',
                'project': result
            }
        except Exception as e:
            logger.error(f"在GitLab上创建项目失败: {e}")
            return {
                'success': False,
                'message': f'创建项目失败: {str(e)}'
            }

    def sync_projects(self) -> Dict[str, Any]:
        """同步项目"""
        try:
            projects = self.client.get_projects()
            logger.info(f"从GitLab获取到 {len(projects)} 个项目")

            # 将GitLab项目同步到本地数据库
            from .models import GitLabProject, Project, Environment
            from django.utils.dateparse import parse_datetime

            synced_count = 0
            for project_data in projects:
                try:
                    # 获取默认项目和环境（仅用于新项目，且不强制设置）
                    default_project = Project.objects.first()
                    default_environment = Environment.objects.filter(code='dev').first()

                    # 检查是否已存在
                    try:
                        gitlab_project = GitLabProject.objects.get(
                            gitlab_server=self.gitlab_server,
                            gitlab_id=project_data['id']
                        )
                        # 已存在，只更新GitLab相关字段，保留用户配置的项目和环境
                        gitlab_project.name = project_data['name']
                        gitlab_project.path = project_data['path']
                        gitlab_project.path_with_namespace = project_data['path_with_namespace']
                        gitlab_project.description = project_data.get('description', '')
                        gitlab_project.web_url = project_data['web_url']
                        gitlab_project.ssh_url_to_repo = project_data['ssh_url_to_repo']
                        gitlab_project.http_url_to_repo = project_data['http_url_to_repo']
                        gitlab_project.visibility = project_data['visibility']
                        gitlab_project.default_branch = project_data.get('default_branch')
                        gitlab_project.star_count = project_data.get('star_count', 0)
                        gitlab_project.forks_count = project_data.get('forks_count', 0)
                        gitlab_project.last_activity_at = parse_datetime(project_data.get('last_activity_at')) if project_data.get('last_activity_at') else None
                        gitlab_project.save()
                        created = False
                    except GitLabProject.DoesNotExist:
                        # 不存在，创建新记录（不设置默认项目和环境）
                        gitlab_project = GitLabProject.objects.create(
                            gitlab_server=self.gitlab_server,
                            gitlab_id=project_data['id'],
                            project=None,  # 新项目不设置默认项目
                            environment=None,  # 新项目不设置默认环境
                            name=project_data['name'],
                            path=project_data['path'],
                            path_with_namespace=project_data['path_with_namespace'],
                            description=project_data.get('description', ''),
                            web_url=project_data['web_url'],
                            ssh_url_to_repo=project_data['ssh_url_to_repo'],
                            http_url_to_repo=project_data['http_url_to_repo'],
                            visibility=project_data['visibility'],
                            default_branch=project_data.get('default_branch'),
                            star_count=project_data.get('star_count', 0),
                            forks_count=project_data.get('forks_count', 0),
                            last_activity_at=parse_datetime(project_data.get('last_activity_at')) if project_data.get('last_activity_at') else None,
                        )
                        created = True
                    synced_count += 1
                    logger.info(f"成功同步项目: {project_data['name']} ({'创建' if created else '更新'})")
                except Exception as e:
                    logger.error(f"同步项目 {project_data.get('name', 'unknown')} 失败: {e}")
                    import traceback
                    logger.error(traceback.format_exc())
                    continue

            return {
                'success': True,
                'message': f'成功同步 {synced_count} 个项目',
                'count': synced_count
            }
        except Exception as e:
            logger.error(f"同步项目失败: {e}")
            import traceback
            logger.error(traceback.format_exc())
            return {
                'success': False,
                'message': f'同步项目失败: {str(e)}'
            }

    def sync_users(self) -> Dict[str, Any]:
        """同步用户"""
        try:
            users = self.client.get_users()
            logger.info(f"从GitLab获取到 {len(users)} 个用户")

            # 将GitLab用户同步到本地数据库
            from .models import GitLabUser
            from django.utils.dateparse import parse_datetime

            synced_count = 0
            for user_data in users:
                try:
                    # 创建或更新GitLab用户
                    gitlab_user, created = GitLabUser.objects.update_or_create(
                        gitlab_server=self.gitlab_server,
                        gitlab_id=user_data['id'],
                        defaults={
                            'username': user_data['username'],
                            'name': user_data['name'],
                            'email': user_data['email'],
                            'state': user_data['state'],
                            'avatar_url': user_data.get('avatar_url', ''),
                            'web_url': user_data['web_url'],
                            'is_admin': user_data.get('is_admin', False),
                        }
                    )
                    synced_count += 1
                    logger.info(f"成功同步用户: {user_data['username']} ({'创建' if created else '更新'})")
                except Exception as e:
                    logger.error(f"同步用户 {user_data.get('username', 'unknown')} 失败: {e}")
                    import traceback
                    logger.error(traceback.format_exc())
                    continue

            return {
                'success': True,
                'message': f'成功同步 {synced_count} 个用户',
                'count': synced_count
            }
        except Exception as e:
            logger.error(f"同步用户失败: {e}")
            import traceback
            logger.error(traceback.format_exc())
            return {
                'success': False,
                'message': f'同步用户失败: {str(e)}'
            }

    def configure_project_webhook(self, project_id: int, webhook_url: str) -> Dict[str, Any]:
        """为项目配置Webhook"""
        try:
            # 先检查是否已经存在相同的Webhook
            existing_hooks = self.client.get_webhooks(project_id)

            # 检查是否已经存在相同URL的Webhook
            for hook in existing_hooks:
                if hook.get('url') == webhook_url:
                    return {
                        'success': True,
                        'message': 'Webhook已存在，无需重复配置',
                        'webhook_id': hook.get('id')
                    }

            # 创建新的Webhook
            result = self.client.create_webhook(project_id, webhook_url)

            logger.info(f"成功为项目 {project_id} 配置Webhook: {webhook_url}")
            return {
                'success': True,
                'message': '成功配置Webhook',
                'webhook_id': result.get('id'),
                'webhook_url': webhook_url
            }

        except Exception as e:
            logger.error(f"为项目 {project_id} 配置Webhook失败: {e}")
            return {
                'success': False,
                'message': f'配置Webhook失败: {str(e)}'
            }

    def get_project_branches(self, project_id):
        """获取项目分支"""
        try:
            url = f"{self.gitlab_server.url}/api/v4/projects/{project_id}/repository/branches"
            headers = {
                'Private-Token': self.gitlab_server.token
            }

            response = requests.get(url, headers=headers, timeout=30)
            response.raise_for_status()

            branches = response.json()
            logger.info(f"成功获取项目 {project_id} 的 {len(branches)} 个分支")
            return {
                'success': True,
                'data': branches
            }
        except Exception as e:
            logger.error(f"获取项目分支失败: {e}")
            return {
                'success': False,
                'message': f'获取分支失败: {str(e)}'
            }

    def get_project_tags(self, project_id):
        """获取项目标签"""
        try:
            url = f"{self.gitlab_server.url}/api/v4/projects/{project_id}/repository/tags"
            headers = {
                'Private-Token': self.gitlab_server.token
            }

            response = requests.get(url, headers=headers, timeout=30)
            response.raise_for_status()

            tags = response.json()
            logger.info(f"成功获取项目 {project_id} 的 {len(tags)} 个标签")
            return {
                'success': True,
                'data': tags
            }
        except Exception as e:
            logger.error(f"获取项目标签失败: {e}")
            return {
                'success': False,
                'message': f'获取标签失败: {str(e)}'
            }

    def sync_local_users_to_gitlab(self) -> Dict[str, Any]:
        """同步本地用户到GitLab"""
        try:
            from django.contrib.auth.models import User
            from .models import GitLabUser
            import secrets
            import string

            local_users = User.objects.filter(is_active=True)
            logger.info(f"准备同步 {len(local_users)} 个本地用户到GitLab")

            synced_count = 0
            created_count = 0
            updated_count = 0

            for local_user in local_users:
                try:
                    # 检查是否已经有对应的GitLab用户
                    existing_gitlab_user = GitLabUser.objects.filter(
                        gitlab_server=self.gitlab_server,
                        local_user=local_user
                    ).first()

                    if existing_gitlab_user:
                        logger.info(f"用户 {local_user.username} 已经映射到GitLab用户 {existing_gitlab_user.username}")
                        continue

                    # 检查GitLab上是否已经存在同名用户
                    try:
                        existing_users = self.client.get_users()
                        existing_usernames = [u['username'] for u in existing_users]

                        if local_user.username in existing_usernames:
                            logger.info(f"GitLab上已存在用户名 {local_user.username}，跳过创建")
                            continue
                    except Exception as e:
                        logger.warning(f"检查现有用户时出错: {e}")

                    # 生成随机密码
                    password = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(12))

                    # 在GitLab上创建用户
                    user_data = {
                        'username': local_user.username,
                        'name': f"{local_user.first_name} {local_user.last_name}".strip() or local_user.username,
                        'email': local_user.email or f"{local_user.username}@example.com",
                        'password': password,
                        'skip_confirmation': True
                    }

                    gitlab_user_data = self.client.create_user(user_data)

                    # 在本地创建GitLab用户记录
                    gitlab_user = GitLabUser.objects.create(
                        gitlab_server=self.gitlab_server,
                        gitlab_id=gitlab_user_data['id'],
                        username=gitlab_user_data['username'],
                        name=gitlab_user_data['name'],
                        email=gitlab_user_data['email'],
                        state=gitlab_user_data['state'],
                        avatar_url=gitlab_user_data.get('avatar_url', ''),
                        web_url=gitlab_user_data['web_url'],
                        is_admin=gitlab_user_data.get('is_admin', False),
                        local_user=local_user
                    )

                    created_count += 1
                    synced_count += 1
                    logger.info(f"成功在GitLab上创建用户 {local_user.username}")

                except Exception as e:
                    logger.error(f"同步用户 {local_user.username} 失败: {e}")
                    continue

            logger.info(f"同步完成: 总共处理 {len(local_users)} 个用户，成功同步 {synced_count} 个，创建 {created_count} 个")

            return {
                'success': True,
                'message': f'成功同步 {synced_count} 个本地用户到GitLab',
                'count': synced_count,
                'created': created_count,
                'updated': updated_count
            }

        except Exception as e:
            logger.error(f"同步本地用户到GitLab失败: {e}")
            logger.error(traceback.format_exc())
            return {
                'success': False,
                'message': f'同步本地用户到GitLab失败: {str(e)}'
            }
